# GSICoreAnalysis project Makefile (authored from roadmap analysis on 2025-10-28).
# Running `make` prints programme and sub-project tasks with status markers.

.PHONY: all summary todo done gate gate.parity parity.gate update next prev help streams stream.summary stream.todo stream.done lint \
        mark mark.start mark.done mark.block mark.wait mark.optional

MAKEFILE_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
REPO_ROOT := $(abspath $(MAKEFILE_DIR)../..)
PROJECT_ROOT ?= /home/linden/code/julia/GSICoreAnalysis.jl
INC_PATH ?= $(PROJECT_ROOT) .
MAKEFLAGS += $(foreach dir,$(INC_PATH),-I $(dir))
SUCCESS_SEARCH_DIRS := $(strip $(foreach dir,$(INC_PATH),$(abspath $(dir))))
TASKS_CLI := $(REPO_ROOT)/scripts/tasks_cli.py
CATALOG_ROOT := $(MAKEFILE_DIR)includes
SUCCESS_DEFAULT_DIR := logs/gsi/success
PYTHON ?= python3

define REGISTER_SUCCESS
$(eval SUCCESS_$(1) := $(2))
endef

success_relative = $(if $(SUCCESS_$(1)),$(SUCCESS_$(1)),$(SUCCESS_DEFAULT_DIR)/$(1).md)
success_absolute = $(if $(filter /%,$(call success_relative,$(1))),$(call success_relative,$(1)))
success_candidates = $(if $(call success_absolute,$(1)),$(call success_absolute,$(1)),$(foreach dir,$(SUCCESS_SEARCH_DIRS),$(dir)/$(call success_relative,$(1))))
success_resolved = $(firstword $(foreach path,$(call success_candidates,$(1)),$(strip $(wildcard $(path)))))
success_exists = $(if $(strip $(call success_resolved,$(1))),true,)
success_display = $(if $(strip $(call success_resolved,$(1))),$(call success_resolved,$(1)),$(firstword $(call success_candidates,$(1))))
effective_status = $(if $(call success_exists,$(1)),done,$(STATUS_$(1)))

NEXT_ARGS := $(filter-out next,$(MAKECMDGOALS))
NEXT_INDEX_RAW := $(firstword $(NEXT_ARGS))
NEXT_INDEX := $(strip $(shell if [ -n "$(NEXT_INDEX_RAW)" ] && printf '%s' "$(NEXT_INDEX_RAW)" | grep -Eq '^[0-9]+$$'; then echo "$(NEXT_INDEX_RAW)"; else echo 1; fi))
NEXT_ARG_IS_NUM := $(strip $(shell if [ -n "$(NEXT_INDEX_RAW)" ] && printf '%s' "$(NEXT_INDEX_RAW)" | grep -Eq '^[0-9]+$$'; then echo 1; else echo 0; fi))

PREV_ARGS := $(filter-out prev,$(MAKECMDGOALS))
PREV_INDEX_RAW := $(firstword $(PREV_ARGS))
PREV_INDEX := $(strip $(shell if [ -n "$(PREV_INDEX_RAW)" ] && printf '%s' "$(PREV_INDEX_RAW)" | grep -Eq '^[0-9]+$$'; then echo "$(PREV_INDEX_RAW)"; else echo 1; fi))
PREV_ARG_IS_NUM := $(strip $(shell if [ -n "$(PREV_INDEX_RAW)" ] && printf '%s' "$(PREV_INDEX_RAW)" | grep -Eq '^[0-9]+$$'; then echo 1; else echo 0; fi))

ifneq (,$(filter next,$(MAKECMDGOALS)))
ifeq ($(NEXT_ARG_IS_NUM),1)
.PHONY: $(NEXT_INDEX_RAW)
$(NEXT_INDEX_RAW):
	@:
endif
endif

ifneq (,$(filter prev,$(MAKECMDGOALS)))
ifeq ($(PREV_ARG_IS_NUM),1)
.PHONY: $(PREV_INDEX_RAW)
$(PREV_INDEX_RAW):
	@:
endif
endif

all: summary

summary: ## List all tasks with status indicators
	$(info GSICoreAnalysis Task Rollup (2025-10-28))
	$(foreach stream,$(STREAM_ORDER),$(call PRINT_STREAM,$(stream)))
	@:

todo: ## Show active, waiting, or optional tasks
	$(info GSICoreAnalysis Pending Tasks)
	$(foreach stream,$(STREAM_ORDER),$(call PRINT_STREAM_FILTER,$(stream),todo wip waiting blocked optional))
	@:

done: ## Show completed tasks
	$(info GSICoreAnalysis Completed Tasks)
	$(foreach stream,$(STREAM_ORDER),$(call PRINT_STREAM_FILTER,$(stream),done))
	@:

next: ## Show the next recommended task and implementation prompt
	$(if $(strip $(next_task)),$(info Next task to execute (position $(NEXT_INDEX) of $(pending_total)):)$(info $(call format_task,$(next_task)))$(call PRINT_NEXT_PROMPT,$(next_task)),$(if $(strip $(pending_queue)),$(info Requested index $(NEXT_INDEX) exceeds pending task count $(pending_total).)$(info Use make \"next $(pending_total)\" to view the last pending task.),$(info All GSICoreAnalysis tasks are complete.)))
	@:

prev: ## Show the most recently completed task (pass index to step further back)
	$(if $(strip $(prev_task)),$(info Most recently completed task (position $(PREV_INDEX) of $(completed_total)):)$(info $(call format_task,$(prev_task)))$(call PRINT_PREV_PROMPT,$(prev_task)),$(if $(completed_total),$(info Requested index $(PREV_INDEX) exceeds completed task count $(completed_total).)$(info Use make \"prev $(completed_total)\" to view the oldest completed task.),$(info No completed GSICoreAnalysis tasks found yet.)))
	@:

streams: ## List stream labels
	$(info GSICoreAnalysis Streams)
	$(foreach stream,$(STREAM_ORDER),$(info $(stream): $(call stream_label,$(stream))))
	@:

help: ## Print available targets
	$(info Available targets:)
	$(info   make            - alias for make summary)
	$(info   make summary    - list all tasks with status markers)
	$(info   make todo       - show pending or optional tasks)
	$(info   make done       - show completed tasks)
	$(info   make mark TASK=ID STATUS=... [OWNER=...] - update catalogue status/metadata)
	$(info   make mark.start TASK=ID - shortcut for STATUS=wip)
	$(info   make mark.done  TASK=ID - shortcut for STATUS=done)
	$(info   make mark.block TASK=ID - shortcut for STATUS=blocked)
	$(info   make mark.wait  TASK=ID - shortcut for STATUS=waiting)
	$(info   make mark.optional TASK=ID - shortcut for STATUS=optional)
	$(info   OWNER=<name> / TAGS="tag1 tag2" filter stream.* output)
	$(info   make update     - auto-mark tasks with success indicators)
	$(info   make next       - show the next actionable task with guidance)
	$(info   make prev       - show the most recent completed task (supports numeric index))
	$(info   make streams    - show stream key)
	$(info   make gate       - validate evidence artefacts for completed tasks)
	$(info   make gate.parity - validate parity-tagged evidence (alias: make parity.gate))
	@:

stream.summary: ## Show selected streams in STREAMS variable
	$(if $(strip $(STREAMS)),$(info GSICoreAnalysis Stream Summary ($(STREAMS)))$(foreach stream,$(STREAMS),$(call PRINT_STREAM,$(stream))),$(error STREAMS not set for stream.summary))
	@:

stream.todo: ## Show pending tasks for selected streams (STREAMS="SP2 SP3")
	$(if $(strip $(STREAMS)),$(info GSICoreAnalysis Stream Pending ($(STREAMS)))$(foreach stream,$(STREAMS),$(call PRINT_STREAM_FILTER,$(stream),todo wip waiting blocked optional)),$(error STREAMS not set for stream.todo))
	@:

stream.done: ## Show completed tasks for selected streams (STREAMS="SP2 SP3")
	$(if $(strip $(STREAMS)),$(info GSICoreAnalysis Stream Completed ($(STREAMS)))$(foreach stream,$(STREAMS),$(call PRINT_STREAM_FILTER,$(stream),done)),$(error STREAMS not set for stream.done))
	@:

lint: ## Validate dependency ordering (warn if prerequisites incomplete)
	$(info GSICoreAnalysis Dependency Check)
	$(foreach task,$(DEP_TARGETS),$(call CHECK_TASK_DEPS,$(task)))
	@:

mark: ## Update task STATUS/metadata (TASK=<ID> STATUS=todo|wip|done|blocked|waiting|optional)
	@if [ -z "$(TASK)" ]; then \
	  echo "TASK= required (e.g., GSI_SP5_AUTOREGRESSION)" 1>&2; \
	  exit 2; \
	fi
	@if [ -z "$(STATUS)" ]; then \
	  echo "STATUS= required (todo|wip|done|blocked|waiting|optional)" 1>&2; \
	  exit 2; \
	fi
	@$(PYTHON) $(TASKS_CLI) set --root $(CATALOG_ROOT) --task $(TASK) --status $(STATUS)$(if $(OWNER), --owner "$(OWNER)",)$(if $(DUE), --due "$(DUE)",)$(if $(PRIO), --prio "$(PRIO)",)$(if $(TAGS), --tags "$(TAGS)",)$(if $(CRIT), --crit "$(CRIT)",)$(if $(EVID), --evid "$(EVID)",)

mark.start mark.done mark.block mark.wait mark.optional: ## Convenience wrappers for common statuses
	@if [ -z "$(TASK)" ]; then \
	  echo "TASK= required (e.g., GSI_SP5_AUTOREGRESSION)" 1>&2; \
	  exit 2; \
	fi
	@status=$(if $(filter mark.start,$@),wip,$(if $(filter mark.done,$@),done,$(if $(filter mark.block,$@),blocked,$(if $(filter mark.wait,$@),waiting,optional)))); \
	$(MAKE) --no-print-directory -f $(firstword $(MAKEFILE_LIST)) mark TASK="$(TASK)" STATUS="$$status" OWNER="$(OWNER)" DUE="$(DUE)" PRIO="$(PRIO)" TAGS="$(TAGS)" CRIT="$(CRIT)" EVID="$(EVID)"

# --- Task registration framework -------------------------------------------------

define REGISTER_TASK
$(eval TASK_IDS += $(1))
$(eval STATUS_$(1) := $(2))
$(eval CLASS_$(1) := $(3))
$(eval STREAM_$(1) := $(4))
$(eval TITLE_$(1) := $(5))
$(eval REF_$(1) := $(6))
endef

define REGISTER_META
$(eval OWNER_$(1) := $(2))
$(eval DUE_$(1) := $(3))
$(eval PRIO_$(1) := $(4))
$(eval TAGS_$(1) := $(5))
$(eval CRIT_$(1) := $(6))
$(eval EVID_$(1) := $(7))
endef

STATUS_EMOJI_done := [x]
STATUS_EMOJI_wip := [~]
STATUS_EMOJI_blocked := [!]
STATUS_EMOJI_waiting := [?]
STATUS_EMOJI_optional := ( )

status_symbol = $(or $(STATUS_EMOJI_$(1)),[ ])
class_badge = $(if $(filter optional,$(1)),[O],[E])
stream_label = $(or $(STREAM_LABEL_$(1)),$(1))

OWNER_FILTER := $(strip $(OWNER))
TAG_FILTER := $(strip $(TAGS))

define APPLY_OWNER_FILTER
$(if $1,$(if $(OWNER_FILTER),$(if $(filter $(OWNER_FILTER),$(OWNER_$1)),$1,),$1),)
endef

define APPLY_TAG_FILTER
$(if $1,$(if $(TAG_FILTER),$(firstword $(foreach tag,$(TAG_FILTER),$(if $(filter $(tag),$(TAGS_$1)),$1))),$1),)
endef

FILTERED_TASKS = $(strip $(foreach t,$(TASK_IDS),$(call APPLY_TAG_FILTER,$(call APPLY_OWNER_FILTER,$(t)))))

tasks_for_stream = $(strip $(foreach t,$(FILTERED_TASKS),$(if $(filter $(1),$(STREAM_$(t))),$(t),)))
tasks_for_stream_status = $(strip $(foreach t,$(call tasks_for_stream,$(1)),$(if $(filter $(call effective_status,$(t)),$(2)),$(t),)))

define reverse_list
$(if $1,$(call reverse_list,$(wordlist 2,$(words $1),$1)) $(firstword $1))
endef

define format_task
$(call status_symbol,$(call effective_status,$(1))) $(call class_badge,$(CLASS_$(1))) $(1) - $(TITLE_$(1)) [$(REF_$(1))]
endef

PENDING_STATUSES := todo wip waiting blocked optional
ORDERED_PENDING_ALL := $(strip $(shell $(PYTHON) $(TASKS_CLI) order --root $(CATALOG_ROOT)))
ORDERED_PENDING := $(strip $(foreach t,$(ORDERED_PENDING_ALL),$(if $(filter $(t),$(FILTERED_TASKS)),$(if $(filter $(call effective_status,$(t)),$(PENDING_STATUSES)),$(if $(call success_exists,$(t)),,$(t))))))
fallback_pending_essential = $(strip $(foreach t,$(FILTERED_TASKS),$(if $(filter essential,$(CLASS_$(t))),$(if $(filter $(call effective_status,$(t)),$(PENDING_STATUSES)),$(if $(call success_exists,$(t)),,$(t))),)))
fallback_pending_optional = $(strip $(foreach t,$(FILTERED_TASKS),$(if $(filter optional,$(CLASS_$(t))),$(if $(filter $(call effective_status,$(t)),$(PENDING_STATUSES)),$(if $(call success_exists,$(t)),,$(t))),)))
fallback_pending = $(strip $(fallback_pending_essential) $(fallback_pending_optional))
pending_queue = $(strip $(if $(ORDERED_PENDING),$(ORDERED_PENDING),$(fallback_pending)))
pending_total = $(words $(pending_queue))
next_task = $(word $(NEXT_INDEX),$(pending_queue))
task_dependencies = $(if $(strip $(DEPS_$(1))),$(DEPS_$(1)),none)

COMPLETED_STATUSES := done
ORDERED_DONE_ALL := $(strip $(shell $(PYTHON) $(TASKS_CLI) order --root $(CATALOG_ROOT) --statuses $(COMPLETED_STATUSES)))
FILTERED_DONE = $(strip $(foreach t,$(FILTERED_TASKS),$(if $(filter done,$(call effective_status,$(t))),$(t),)))
ORDERED_DONE = $(strip $(foreach t,$(ORDERED_DONE_ALL),$(if $(filter $(t),$(FILTERED_DONE)),$(t))))
fallback_done = $(FILTERED_DONE)
completed_queue = $(strip $(if $(ORDERED_DONE),$(ORDERED_DONE),$(fallback_done)))
completed_queue_rev = $(strip $(call reverse_list,$(completed_queue)))
completed_total = $(words $(completed_queue_rev))
prev_task = $(word $(PREV_INDEX),$(completed_queue_rev))

define PRINT_NEXT_PROMPT
$(info Implementation prompt:)
$(info   - Objective: $(TITLE_$(1)))
$(info   - Stream: $(call stream_label,$(STREAM_$(1))))
$(info   - Current status: $(call effective_status,$(1)) ($(CLASS_$(1))))
$(info   - Dependencies: $(call task_dependencies,$(1)))
$(if $(strip $(DEPS_$(1))),$(foreach dep,$(DEPS_$(1)),$(info     • $(dep): status=$(call effective_status,$(dep)) success=$(call success_display,$(dep)))))
$(info   - Reference doc: $(REF_$(1)))
$(info   - Success indicator: $(call success_display,$(1)))
$(info     Search order: $(SUCCESS_SEARCH_DIRS))
$(info   - Suggested actions:)
$(info     1. Review dependencies and confirm prerequisites are satisfied.)
$(info     2. Execute the required changes and collect artefacts/evidence.)
$(info     3. Update the catalogue entry (mark target) and note outcomes in worklogs.)
$(info   - Sequence coverage: $(NEXT_INDEX) / $(pending_total))
$(info )
endef

define PRINT_PREV_PROMPT
$(info Completion recap:)
$(info   - Objective: $(TITLE_$(1)))
$(info   - Stream: $(call stream_label,$(STREAM_$(1))))
$(info   - Current status: $(call effective_status,$(1)) ($(CLASS_$(1))))
$(info   - Dependencies: $(call task_dependencies,$(1)))
$(if $(strip $(DEPS_$(1))),$(foreach dep,$(DEPS_$(1)),$(info     • $(dep): status=$(call effective_status,$(dep)) success=$(call success_display,$(dep)))))
$(info   - Reference doc: $(REF_$(1)))
$(info   - Success indicator: $(call success_display,$(1)))
$(info     Search order: $(SUCCESS_SEARCH_DIRS))
$(info   - Follow-up ideas:)
$(info     1. Review artefacts to confirm evidence paths remain valid.)
$(info     2. Capture retrospective notes or update parity dashboards if needed.)
$(info   - Sequence coverage: $(PREV_INDEX) / $(completed_total))
$(info )
endef

define PRINT_STREAM
$(if $(call tasks_for_stream,$(1)),$(info )$(info -- $(call stream_label,$(1)) --)$(foreach t,$(call tasks_for_stream,$(1)),$(info $(call format_task,$(t)))))
endef

define PRINT_STREAM_FILTER
$(if $(call tasks_for_stream_status,$(1),$(2)),$(info )$(info -- $(call stream_label,$(1)) --)$(foreach t,$(call tasks_for_stream_status,$(1),$(2)),$(info $(call format_task,$(t)))))
endef

DEP_TARGETS :=

define REGISTER_DEP
$(eval DEPS_$(1) := $(strip $(DEPS_$(1)) $(2)))
$(eval DEP_TARGETS := $(sort $(DEP_TARGETS) $(1)))
endef

define CHECK_TASK_DEPS
$(foreach dep,$(DEPS_$(1)),$(if $(and $(filter done,$(STATUS_$(1))),$(filter-out done,$(STATUS_$(dep)))),\
$(warning $(1) marked done but prerequisite $(dep) is $(STATUS_$(dep))),))
endef

include $(MAKEFILE_DIR)includes/meta.mk

# --- Task catalogue --------------------------------------------------------------

include $(MAKEFILE_DIR)includes/tasks.mk

GATE_STATUSES := done
GATE_TASKS := GSI_SP5_BACKEND_AUTO GSI_SP5_WIND_VARIANCE GSI_SP5_DRP_RUNTIME

gate: ## Validate evidence artefacts for critical completed tasks
	@$(PYTHON) $(TASKS_CLI) gate --root $(CATALOG_ROOT) --repo $(PROJECT_ROOT) --extra-repos "$(REPO_ROOT)" --statuses "$(GATE_STATUSES)" --tasks "$(GATE_TASKS)"

gate.parity: ## Validate parity-tagged tasks have the required evidence
	@$(PYTHON) $(TASKS_CLI) gate --root $(CATALOG_ROOT) --repo $(PROJECT_ROOT) --extra-repos "$(REPO_ROOT)" --statuses "$(GATE_STATUSES)" --tags "parity" --tasks "$(GATE_TASKS)"

parity.gate: ## Alias for gate.parity (deprecated name)
	@$(MAKE) --no-print-directory -f $(firstword $(MAKEFILE_LIST)) gate.parity

update: ## Mark successive tasks as done when success indicators exist
	@$(PYTHON) $(TASKS_CLI) autodone --root $(CATALOG_ROOT) --repo $(PROJECT_ROOT) --extra-success-roots "$(REPO_ROOT)" --success-dir $(SUCCESS_DEFAULT_DIR)
